package cc.owoo.godpen.structure;

import java.util.LinkedList;

/**
 * Byte池，非线程安全的，在多线程下请手动加锁
 * Created by nimensei
 * 2022-02-26 下午 05:50
 **/
public class ByteList {
    private final LinkedList<byte[]> poolList = new LinkedList<>();// 池子列表
    private byte[] pool;// 当前池子
    private int poolSize;// 每个池子的大小
    private int index;// 当前池子位置
    private int size = 0;// 当前总长度

    public ByteList() {
        this(1024);
    }

    /**
     * 创建池子大小
     *
     * @param poolSize 池子大小
     */
    public ByteList(int poolSize) {
        setPoolSize(poolSize);
        this.pool = new byte[this.poolSize];
    }

    /**
     * 设置每个池子的大小
     *
     * @param poolSize 池子大小
     */
    public void setPoolSize(int poolSize) {
        poolSize = Math.max(1, poolSize);
        this.poolSize = poolSize;
    }

    /**
     * 写入一个byte
     *
     * @param c byte
     */
    public void write(int c) {
        pool[index++] = (byte) c;
        if (index == pool.length)
            renewal();
        ++size;
    }

    /**
     * 写入byte数组
     *
     * @param bytes byte数组
     */
    public void write(byte[] bytes) {
        write(bytes, 0, bytes.length);
    }

    /**
     * 写入byte数组
     *
     * @param bytes byte数组
     * @param off   开始位置
     * @param len   从开始位置起的长度
     */
    public void write(byte[] bytes, int off, int len) {
        len = Math.min(bytes.length - off, len);
        if (len == 0)
            return;
        size += len;
        int now;
        while (true) {
            now = pool.length - index;
            if (now > len) {
                System.arraycopy(bytes, off, pool, index, len);
                index += len;
                break;
            }
            System.arraycopy(bytes, off, pool, index, now);
            renewal();
            len -= now;
            off += now;
        }
    }

    /**
     * 向池子里添加数组
     *
     * @param bytes  数组
     * @param offset 偏移位置
     */
    public void append(byte[] bytes, int offset) {
        append(bytes, offset, bytes.length - offset);
    }

    /**
     * 向池子里添加数组
     *
     * @param bytes 数组
     */
    public void append(byte[] bytes) {
        if (bytes == null || bytes.length == 0)
            return;
        poolList.add(bytes);
        size += bytes.length;
    }

    /**
     * 向池子里添加数组
     *
     * @param bytes  数组
     * @param offset 偏移位置
     * @param len    从偏移位置开始计算的长度
     */
    public void append(byte[] bytes, int offset, int len) {
        if (bytes == null || bytes.length == 0 || offset > bytes.length)
            return;
        len = Math.min(bytes.length - offset, len);
        byte[] temp = new byte[len];
        System.arraycopy(bytes, offset, temp, 0, len);
        append(temp);
    }

    /**
     * 更换新池子
     */
    private void renewal() {
        poolList.add(pool);
        pool = new byte[poolSize];
        index = 0;
    }

    /**
     * 获取当前写入的byte数量
     *
     * @return byte数量
     */
    public int size() {
        return size;
    }

    /**
     * 重置池子
     */
    public void reset() {
        poolList.clear();
        index = 0;
        size = 0;
    }

    /**
     * 将所有池子合成为一个byte数组，该函数不带缓存，因此未对数据进行更改的情况下，勿频繁调用
     *
     * @return byte数组
     */
    public byte[] toByteArray() {
        byte[] bytes = new byte[size];
        int off = 0;
        for (byte[] pool : poolList) {
            System.arraycopy(pool, 0, bytes, off, pool.length);
            off += pool.length;
        }
        if (index > 0)
            System.arraycopy(pool, 0, bytes, off, index);
        return bytes;
    }

    @Override
    public String toString() {
        return new String(toByteArray());
    }
}
